const WS = require('ws');
// const webSocket = require('websocket');
const commander = require('commander');
const readline = require('readline');


function waitInput() {
	return new Promise((resolve, reject) => {
		const rl = readline.createInterface({
			input: process.stdin,
			output: process.stdout
		});

		rl.question('>', (userInput) => {
			rl.close();
			resolve(userInput);
		});
	});
}

// 测试端口是否可用
function checkPort(port) {
	return new Promise((resolve, reject) => {
		const net = require('net');
		const tester = net.createServer()
			.on('error', function(err) {
				if (err.code != 'EADDRINUSE') return reject(err);
				tester.close();
				resolve(false);
			})
			.on('listening', function() {
				tester.close();
				resolve(true); 
			})
			.listen(port);		
	})
}

class App {
	async startServer({ port = 8080 }) {
		const res = await checkPort(port);
		if (!res) {
			console.log(`端口${port}被占用，请更换端口号`);
			waitInput().then(input => this.parseCommons(input));
			return;
		}
		const WebSocketServer = WS.Server;

		//在8080端口上打开了一个WebSocket Server，该实例由变量wss引用。
		const wss = new WebSocketServer({
			port,
			perMessageDeflate: {
				zlibDeflateOptions: { // See zlib defaults.
					chunkSize: 64,
					memLevel: 2,
					level: 1,
				},
				clientMaxWindowBits: 8
			}
		});

		//如果有WebSocket请求接入，wss对象可以响应connection事件来处理这个WebSocket：
		wss.on('connection', function (ws) {  //在connection事件中，回调函数会传入一个WebSocket的实例，表示这个WebSocket连接。
			console.log(`[SERVER] new connection.`, ws.upgradeReq);
			ws.on('message', function (message) {  //我们通过响应message事件，在收到消息后再返回一个ECHO: xxx的消息给客户端。
				console.log(`[SERVER] Received: ${message}`);
				ws.send(`${message}`, (err) => {
					if (err) {
						console.log(`[SERVER] error:${err}`);
					}
				});
			});

			ws.on('close', function (err) {  //在connection事件中，回调函数会传入一个WebSocket的实例，表示这个WebSocket连接。
				console.log(`[SERVER] close.`);
				console.log(err)
			});

			ws.on('open', function (ws) {
				console.log(`[SERVER] New connection `, ws);
			});
		});

		console.log(`[SERVER] WebSocket server running on port ${port}...`);
	}

	startClient({ url = "ws://localhost:8089" }) {
		const socket = new WS(url);
		const onOpen = async () => {
			const input = await waitInput();
			socket.send(input);
			onOpen();
		}
		socket.on('open', () => {
			console.log('[CLIENT]: connected.');
			onOpen();
		});

		socket.on('message', (message) => {
			const msgStr = message.toString('utf8');
			console.log("[CLIENT] Received: " + msgStr);
		});

		socket.on('error', (error) => {
			console.error("[ERROR]: ", error.toString());
		});

		socket.on('close', () => {
			console.log('[CLIENT]: connection closed.');
		});
	}

	parseCommons(c) {
		// console.log('[input]:', c);
		if(!this.program){
			this.program = commander.program
				.option('-p, --port <number>', '要创建的websocket服务的端口号', '')
				.option('-u, --url <url>', '要连接的websocket服务器地址', '');	
		}

		const commands = c.split(' ');
		if (commands.length < 2) {
			this.program.outputHelp();
			waitInput().then(input => this.parseCommons(input));
			return;
		}

		this.program.parse([...process.argv, ...commands]);

		const options = this.program.opts();

		// console.log(options, [...process.argv, ...commands]);
		if (options.url) {
			this.startClient(options);
		} else if (options.port) {
			this.startServer(options);
		} else {
			console.error("请指定 --port 启动服务端 或 --url 连接服务端");
		}

	}
}

waitInput().then(input => (new App()).parseCommons(input));